#include "QD3DUtils.h"
#include <d3dcompiler.h>
#include <iostream>

QD3DUtils::QD3DUtils (QD3DContext *pContext) : __p_context (pContext)
{
	if (__p_context == NULL)
		throw std::exception ("QD3DUtils::QD3DUtils (): Cannot initialized with null pointer");
}

QD3DUtils::~QD3DUtils ()
{

}

void QD3DUtils::clearRenderTarget (float r, float g, float b, float a)
{
	float c[4] = {r, g, b, a};
	__p_context->pImmediateContext->ClearRenderTargetView (
			__p_context->pRenderTargetView, c);
}

void QD3DUtils::swapBuffers ()
{
	__p_context->pSwapChain->Present (0, 0);
}

void QD3DUtils::setViewport (float left, float top, float width,
		float height, float minDepth, float maxDepth)
{
	D3D11_VIEWPORT vp;
	vp.Width = width;
	vp.Height = height;
	vp.MinDepth = minDepth;
	vp.MaxDepth = maxDepth;
	vp.TopLeftX = left;
	vp.TopLeftY = top;
	__p_context->pImmediateContext->RSSetViewports (1, &vp);
}

void QD3DUtils::setViewports (const QVector< CD3D11_VIEWPORT > &viewports)
{
	__p_context->pImmediateContext->RSSetViewports (viewports.size (),
			&viewports[0]);
}

void QD3DUtils::clearDepthStencil (float depth, float stencil)
{
	__p_context->pImmediateContext->ClearDepthStencilView (
			__p_context->pDepthStencilView, D3D11_CLEAR_DEPTH, depth, stencil);
}

ID3DBlob *QD3DUtils::compileShaderFromFile (const QString &fileName,
		const QString &entryPoint, char *shaderProfile,
		QD3DShaderDesc &shaderDesc)
{
	HRESULT hr = S_OK;
	D3D10_SHADER_MACRO *macroArr = NULL;

	const QMap< std::string, std::string > &defines = shaderDesc.getDefines ();
	if (!defines.empty ()) {
		macroArr = new D3D10_SHADER_MACRO[defines.size () + 1];
		int i = 0;
		for (QMap< std::string, std::string >::const_iterator definesItr =
				defines.begin (); definesItr != defines.end ();
				++definesItr, ++i) {
			macroArr[i].Name = definesItr.key ().c_str ();
			macroArr[i].Definition = definesItr.value ().c_str ();
		}
		macroArr[i].Name = NULL;
		macroArr[i].Definition = NULL;
	}

	ID3DBlob *pErrorBlob = NULL;
	ID3DBlob *pShaderBlob = NULL;
	hr = D3DX11CompileFromFile (fileName.toStdWString ().c_str (),
			macroArr, shaderDesc.getPIncludeFileHandler (),
			entryPoint.toStdString ().c_str (), shaderProfile,
			shaderDesc.getFlags (), 0, NULL, &pShaderBlob, &pErrorBlob, NULL);
	if (macroArr) delete [] macroArr;
	if (FAILED (hr)) {
		if(pErrorBlob != NULL)
			OutputDebugStringA ((char*)pErrorBlob->GetBufferPointer ());
		SAFE_RELEASE (pErrorBlob);
		throw std::exception ("QD3DUtils::_compileShaderFromFile(): "
				"Compile is failure.");
	}
	SAFE_RELEASE (pErrorBlob);
	return pShaderBlob;
}

ID3D11InputLayout * QD3DUtils::createInputLayout (
		const QVector< D3D11_INPUT_ELEMENT_DESC > &inputLayoutDescs,
		ID3DBlob *pShaderBlob)
{
	// Create the input layout
	ID3D11InputLayout *pInputLayout = NULL;
	HRESULT hr = __p_context->pDevice->CreateInputLayout (&inputLayoutDescs[0],
			inputLayoutDescs.size (), pShaderBlob->GetBufferPointer (),
			pShaderBlob->GetBufferSize(), &pInputLayout);
	if (FAILED (hr))
		throw std::exception ("QD3DUtils::createInputLayout(): "
				"fail to create input layout.");
	return pInputLayout;
}

void QD3DUtils::setInputLayout (ID3D11InputLayout *pInputLayout)
{
	__p_context->pImmediateContext->IASetInputLayout (pInputLayout);
}

void QD3DUtils::setShaders (ID3D11VertexShader *pVertexShader,
		ID3D11GeometryShader *pGeometryShader,
		ID3D11PixelShader *pPixelShader)
{
	if (pVertexShader)
		__p_context->pImmediateContext->VSSetShader (pVertexShader, NULL, 0);
	if (pGeometryShader)
		__p_context->pImmediateContext->GSSetShader (pGeometryShader, NULL, 0);
	if (pPixelShader)
		__p_context->pImmediateContext->PSSetShader (pPixelShader, NULL, 0);
}

void QD3DUtils::draw (UINT vertexCount, UINT startLocation)
{
	__p_context->pImmediateContext->Draw (vertexCount, startLocation);
}

void QD3DUtils::drawIndexed (UINT indexCount, UINT startLocation,
		UINT baseVertexLocation)
{
	__p_context->pImmediateContext->DrawIndexed (indexCount, startLocation,
			baseVertexLocation);
}

ID3D11Buffer *QD3DUtils::createBuffer (const CD3D11_BUFFER_DESC &bufferDesc,
		VOID *pData, const std::string &debugName)
{
	ID3D11Buffer *pBufferObj = NULL;
	D3D11_SUBRESOURCE_DATA d3D11Data = { pData, 0, 0 };
	HRESULT hr = __p_context->pDevice->CreateBuffer (&bufferDesc,
			(pData == NULL ? NULL : &d3D11Data),
			&pBufferObj);
	if (FAILED (hr))
		throw std::exception ("QD3DUtils::createBuffer(): "
				"fail to create buffer.");
#if defined(DEBUG) || defined(_DEBUG)
	pBufferObj->SetPrivateData (WKPDID_D3DDebugObjectName,
			debugName.size () + 1, debugName.c_str ());
#endif
	return pBufferObj;
}

ID3D11Buffer * QD3DUtils::createRawBuffer (UINT byteSize, VOID* pInitData,
		UINT bindFlags, const std::string &debugName)
{
	CD3D11_BUFFER_DESC desc;
	ZeroMemory (&desc, sizeof (CD3D11_BUFFER_DESC));
	desc.BindFlags = bindFlags;
	desc.ByteWidth = byteSize;
	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
	return createBuffer (desc, pInitData, debugName);
}

ID3D11Buffer * QD3DUtils::createStructuredBuffer (UINT elemCount,
		UINT structSize, VOID *pInitData, UINT bindFlags,
		const std::string &debugName)
{
	CD3D11_BUFFER_DESC desc;
	ZeroMemory (&desc, sizeof (CD3D11_BUFFER_DESC));
	desc.BindFlags = bindFlags;
	desc.ByteWidth = elemCount * structSize;
	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	desc.StructureByteStride = structSize;
	return createBuffer (desc, pInitData, debugName);
}

ID3D11Texture2D * QD3DUtils::createTexture2D (
		const CD3D11_TEXTURE2D_DESC &texDesc,
		const QVector< D3D11_SUBRESOURCE_DATA > &subresourceDataList)
{
	ID3D11Texture2D *pTexObj;
	if (subresourceDataList.empty ())
		__p_context->pDevice->CreateTexture2D (&texDesc, NULL, &pTexObj);
	else
		__p_context->pDevice->CreateTexture2D (&texDesc, &subresourceDataList[0],
				&pTexObj);
	return pTexObj;
}

void QD3DUtils::updateSubresource (ID3D11Resource *pResource, UINT dst,
		const void *pSrcData, const D3D11_BOX *pDstBox, UINT rowPitch,
		UINT depthPitch)
{
	__p_context->pImmediateContext->UpdateSubresource (pResource, dst, pDstBox,
			pSrcData, rowPitch, depthPitch);
}

void QD3DUtils::setVertexBuffers (UINT startSlot,
		const QVector< ID3D11Buffer * > &pVertexBuffers,
		const QVector< UINT > &elemBytesArr,
		const QVector< UINT > &elemOffsetArr)
{
	QVector< UINT > byteOffsets (pVertexBuffers.size ());
	for (int i = 0; i < pVertexBuffers.size (); ++i)
		byteOffsets[i] = elemOffsetArr[i] * elemBytesArr[i];
	__p_context->pImmediateContext->IASetVertexBuffers (startSlot,
			pVertexBuffers.size (), &pVertexBuffers[0], &elemBytesArr[0],
			&byteOffsets[0]);
}

void QD3DUtils::setIndexBuffer (ID3D11Buffer *pIndexBuffer, DXGI_FORMAT format,
		UINT offset)
{
	__p_context->pImmediateContext->IASetIndexBuffer (pIndexBuffer, format, offset);
}

void QD3DUtils::setSRVs (Shader shaderType, UINT startSlot,
		const QVector< ID3D11ShaderResourceView * > &viewPtrs)
{
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetShaderResources (startSlot,
				viewPtrs.size (), &viewPtrs[0]);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetShaderResources (startSlot,
				viewPtrs.size (), &viewPtrs[0]);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetShaderResources (startSlot,
				viewPtrs.size (), &viewPtrs[0]);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetShaderResources (startSlot,
				viewPtrs.size (), &viewPtrs[0]);
		break;
	}
}

void QD3DUtils::clearSRVs (Shader shaderType, UINT startSlot, UINT count)
{
	ID3D11ShaderResourceView **nullPtrs = new ID3D11ShaderResourceView*[count];
	memset (nullPtrs, NULL, sizeof (void*) * count);
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetShaderResources (startSlot,
				count, nullPtrs);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetShaderResources (startSlot,
				count, nullPtrs);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetShaderResources (startSlot,
				count, nullPtrs);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetShaderResources (startSlot,
				count, nullPtrs);
		break;
	}
}

void QD3DUtils::setUAVs (Shader shaderType, UINT startSlot,
	const QVector< ID3D11UnorderedAccessView * > &viewPtrs)
{
	switch (shaderType) {
	case VERTEX_SHADER:
	case GEOMETRY_SHADER:
	case PIXEL_SHADER:
		std::cerr << "WARNING: QD3DUtils::setUnorderedAccessViews()" <<
			"The shader does not support unordered access view." <<
			std::endl;
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetUnorderedAccessViews (startSlot,
			viewPtrs.size (), &viewPtrs[0], NULL);
		break;
	}
}

void QD3DUtils::clearUAVs (Shader shaderType, UINT startSlot, UINT count)
{
	ID3D11UnorderedAccessView **nullPtrs = new ID3D11UnorderedAccessView *[count];
	memset (nullPtrs, NULL, sizeof (void*) * count);
	switch (shaderType) {
	case VERTEX_SHADER:
	case GEOMETRY_SHADER:
	case PIXEL_SHADER:
		std::cerr << "WARNING: QD3DUtils::setUnorderedAccessViews()" <<
				"The shader does not support unordered access view." <<
				std::endl;
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetUnorderedAccessViews (startSlot,
				count, nullPtrs, NULL);
		break;
	}
}

void QD3DUtils::setConstBufs (Shader shaderType, UINT startSlot,
	const QVector< ID3D11Buffer * > &pConstBuffers)
{
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetConstantBuffers (startSlot,
			pConstBuffers.size (), &pConstBuffers[0]);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetConstantBuffers (startSlot,
			pConstBuffers.size (), &pConstBuffers[0]);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetConstantBuffers (startSlot,
			pConstBuffers.size (), &pConstBuffers[0]);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetConstantBuffers (startSlot,
			pConstBuffers.size (), &pConstBuffers[0]);
		break;
	}
}

void QD3DUtils::clearConstBufs (Shader shaderType, UINT startSlot, UINT count)
{
	ID3D11Buffer **nullPtrs = new ID3D11Buffer *[count];
	memset (nullPtrs, NULL, sizeof (void*) * count);
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetConstantBuffers (startSlot,
				count, nullPtrs);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetConstantBuffers (startSlot,
				count, nullPtrs);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetConstantBuffers (startSlot,
				count, nullPtrs);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetConstantBuffers (startSlot,
				count, nullPtrs);
		break;
	}
}

void QD3DUtils::setSamplers (Shader shaderType, UINT startSlot,
		const QVector< ID3D11SamplerState * > &pSamplers)
{
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetSamplers (startSlot,
			pSamplers.size (), &pSamplers[0]);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetSamplers (startSlot,
			pSamplers.size (), &pSamplers[0]);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetSamplers (startSlot,
			pSamplers.size (), &pSamplers[0]);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetSamplers (startSlot,
			pSamplers.size (), &pSamplers[0]);
		break;
	}
}

void QD3DUtils::clearSamplers (Shader shaderType, UINT startSlot, UINT count)
{
	ID3D11SamplerState **nullPtrs = new ID3D11SamplerState *[count];
	memset (nullPtrs, NULL, sizeof (void*) * count);
	switch (shaderType) {
	case VERTEX_SHADER:
		__p_context->pImmediateContext->VSSetSamplers (startSlot,
				count, nullPtrs);
		break;
	case GEOMETRY_SHADER:
		__p_context->pImmediateContext->GSSetSamplers (startSlot,
				count, nullPtrs);
		break;
	case PIXEL_SHADER:
		__p_context->pImmediateContext->PSSetSamplers (startSlot,
				count, nullPtrs);
		break;
	case COMPUTE_SHADER:
		__p_context->pImmediateContext->CSSetSamplers (startSlot,
				count, nullPtrs);
		break;
	}
}

void QD3DUtils::setPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY topology)
{
	__p_context->pImmediateContext->IASetPrimitiveTopology (topology);
}

ID3D11ShaderResourceView* QD3DUtils::createSRV (
		const CD3D11_SHADER_RESOURCE_VIEW_DESC &desc,
		ID3D11Resource *pResource)
{
	ID3D11ShaderResourceView *pSRVOut;
	HRESULT hr = __p_context->pDevice->CreateShaderResourceView (
			pResource, &desc, &pSRVOut);
	if (FAILED (hr))
		throw std::exception ("QD3DUtils::createShaderResourceView()"
				"Fail to create shader resource view.");
	return pSRVOut;
}

ID3D11ShaderResourceView * QD3DUtils::createSRV (ID3D11Resource *pResource)
{
	return createSRV (createDefaultSRVDesc (pResource), pResource);
}

CD3D11_SHADER_RESOURCE_VIEW_DESC QD3DUtils::createDefaultSRVDesc (
		ID3D11Resource *pResource)
{
	CD3D11_SHADER_RESOURCE_VIEW_DESC desc;
	ZeroMemory (&desc, sizeof (CD3D11_SHADER_RESOURCE_VIEW_DESC));
	D3D11_RESOURCE_DIMENSION resDimension;
	pResource->GetType (&resDimension);
	switch (resDimension) {
	case D3D11_RESOURCE_DIMENSION_BUFFER:
		{
			D3D11_BUFFER_DESC buffDesc;
			((ID3D11Buffer *)pResource)->GetDesc (&buffDesc);
			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
			desc.BufferEx.FirstElement = 0;
			if (buffDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) {
				// This is a Raw Buffer
				desc.Format = DXGI_FORMAT_R32_TYPELESS;
				desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
				desc.BufferEx.NumElements = buffDesc.ByteWidth / 4;
			} else if (buffDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
				// This is a Structured Buffer
				desc.Format = DXGI_FORMAT_UNKNOWN;
				desc.BufferEx.NumElements = buffDesc.ByteWidth /
						buffDesc.StructureByteStride;
			} else {
				throw std::exception (
						"QD3DUtils::createDefaultShaderResourceViewDesc(): "
						"Cannot create SRV for the buffer: "
						"it's neither raw buffer nor structured buffer.");
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
		{
			D3D11_TEXTURE1D_DESC texDesc;
			ID3D11Texture1D *pTexture1D = (ID3D11Texture1D*)pResource;
			pTexture1D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			if (texDesc.ArraySize != 1) {
				desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE1DARRAY;
				desc.Texture1DArray.MipLevels = texDesc.MipLevels;
				desc.Texture1DArray.MostDetailedMip = texDesc.MipLevels -1;
				desc.Texture1DArray.ArraySize = texDesc.ArraySize;
			} else {
				desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE1D;
				desc.Texture1D.MipLevels = texDesc.MipLevels;
				desc.Texture1D.MostDetailedMip = texDesc.MipLevels - 1;
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
		{
			D3D11_TEXTURE2D_DESC texDesc;
			ID3D11Texture2D *pTexture2D = (ID3D11Texture2D*)pResource;
			pTexture2D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			if (texDesc.ArraySize != 1) {
				if (texDesc.SampleDesc.Count == 1) {
					desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DARRAY;
					desc.Texture2DArray.MipLevels = texDesc.MipLevels;
					desc.Texture2DArray.MostDetailedMip = texDesc.MipLevels -1;
					desc.Texture2DArray.ArraySize = texDesc.ArraySize;
				} else {
					desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY;
					desc.Texture2DMSArray.ArraySize = texDesc.ArraySize;
				}
			} else {
				if (texDesc.SampleDesc.Count == 1) {
					desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
					desc.Texture2D.MipLevels = texDesc.MipLevels;
					desc.Texture2D.MostDetailedMip = texDesc.MipLevels - 1;
				} else {
					desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DMS;
				}
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
		{
			D3D11_TEXTURE3D_DESC texDesc;
			ID3D11Texture3D *pTexture3D = (ID3D11Texture3D*)pResource;
			pTexture3D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE3D;
			desc.Texture3D.MipLevels = texDesc.MipLevels;
			desc.Texture3D.MostDetailedMip = texDesc.MipLevels - 1;
		}
		break;
	}
	return desc;
}

ID3D11UnorderedAccessView* QD3DUtils::createUAV (
		const CD3D11_UNORDERED_ACCESS_VIEW_DESC &desc,
		ID3D11Resource *pResource)
{
	ID3D11UnorderedAccessView *pUAVOut;
	HRESULT hr = __p_context->pDevice->CreateUnorderedAccessView (pResource,
			&desc, &pUAVOut);
	if (FAILED (hr))
		throw std::exception ("QD3DUtils::createUnorderedAccessView()"
				"Fail to create unordered access view.");
	return pUAVOut;
}

ID3D11UnorderedAccessView * QD3DUtils::createUAV (ID3D11Resource *pResource)
{
	return createUAV (createDefaultUAVDesc (pResource), pResource);
}

CD3D11_UNORDERED_ACCESS_VIEW_DESC QD3DUtils::
		createDefaultUAVDesc (ID3D11Resource *pResource)
{
	CD3D11_UNORDERED_ACCESS_VIEW_DESC desc;
	ZeroMemory (&desc, sizeof (CD3D11_UNORDERED_ACCESS_VIEW_DESC));
	D3D11_RESOURCE_DIMENSION resDimension;
	pResource->GetType (&resDimension);
	switch (resDimension) {
	case D3D11_RESOURCE_DIMENSION_BUFFER:
		{
			D3D11_BUFFER_DESC buffDesc;
			((ID3D11Buffer *)pResource)->GetDesc (&buffDesc);
			desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
			desc.Buffer.FirstElement = 0;
			if (buffDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS) {
				// This is a Raw Buffer
				desc.Format = DXGI_FORMAT_R32_TYPELESS;
				desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
				desc.Buffer.NumElements = buffDesc.ByteWidth / 4;
			} else if (buffDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
				// This is a Structured Buffer
				desc.Format = DXGI_FORMAT_UNKNOWN;
				desc.Buffer.NumElements = buffDesc.ByteWidth /
						buffDesc.StructureByteStride;
			} else {
				throw std::exception (
						"QD3DUtils::createDefaultUnorderedAccessViewDesc(): "
						"Cannot create UAV for the buffer: "
						"it's neither raw buffer nor structured buffer.");
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
		{
			D3D11_TEXTURE1D_DESC texDesc;
			ID3D11Texture1D *pTexture1D = (ID3D11Texture1D*)pResource;
			pTexture1D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			if (texDesc.ArraySize != 1) {
				desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY;
				desc.Texture1DArray.ArraySize = texDesc.ArraySize;
			} else {
				desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D;
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
		{
			D3D11_TEXTURE2D_DESC texDesc;
			ID3D11Texture2D *pTexture2D = (ID3D11Texture2D*)pResource;
			pTexture2D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			if (texDesc.ArraySize != 1) {
				desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
				desc.Texture2DArray.ArraySize = texDesc.ArraySize;
			} else {
				desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
			}
		}
		break;
	case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
		{
			D3D11_TEXTURE3D_DESC texDesc;
			ID3D11Texture3D *pTexture3D = (ID3D11Texture3D*)pResource;
			pTexture3D->GetDesc (&texDesc);
			desc.Format = texDesc.Format;
			desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
			desc.Texture3D.WSize = texDesc.Depth;
		}
		break;
	}
	return desc;
}

void QD3DUtils::copyResource (ID3D11Resource *pDstResource,
		ID3D11Resource *pSrcResource, INT dstSubresource, INT srcSubresource,
		INT dstX, INT dstY, INT dstZ, const D3D11_BOX &srcBox)
{
	if (dstSubresource == -1)
		__p_context->pImmediateContext->CopyResource (pDstResource, pSrcResource);
	else
		__p_context->pImmediateContext->CopySubresourceRegion (pDstResource,
				dstSubresource, dstX, dstY, dstZ, pSrcResource, srcSubresource,
				&srcBox);
}

void QD3DUtils::map (D3D11_MAP mapType, ID3D11Resource *pDstResource,
		D3D11_MAPPED_SUBRESOURCE *pSubResource, UINT subResourceIndex)
{
	__p_context->pImmediateContext->Map (pDstResource, subResourceIndex,
			mapType, 0, pSubResource);
}

void QD3DUtils::unmap (ID3D11Resource *pDstResource, UINT subResourceIndex)
{
	__p_context->pImmediateContext->Unmap (pDstResource, subResourceIndex);
}

void QD3DUtils::setComputeShader (ID3D11ComputeShader *pShader)
{
	if (pShader)
		__p_context->pImmediateContext->CSSetShader (pShader, NULL, 0);
}

void QD3DUtils::dispatch (UINT threadGroupCountX, UINT threadGroupCountY,
		UINT threadGroupCountZ)
{
	__p_context->pImmediateContext->Dispatch (threadGroupCountX,
			threadGroupCountY, threadGroupCountZ);
}

void QD3DUtils::indirectDispatch (ID3D11Buffer *pArgBuffer, UINT offset)
{
	__p_context->pImmediateContext->DispatchIndirect (pArgBuffer, offset);
}

ID3D11SamplerState *QD3DUtils::createSamplerState (
		const CD3D11_SAMPLER_DESC &desc)
{
	ID3D11SamplerState *pSampler;
	__p_context->pDevice->CreateSamplerState (&desc, &pSampler);
	return pSampler;
}

CD3D11_BLEND_DESC QD3DUtils::createTransparentBlendDesc ()
{
	CD3D11_BLEND_DESC blendStateDesc;
	ZeroMemory (&blendStateDesc, sizeof (CD3D11_BLEND_DESC));
	blendStateDesc.AlphaToCoverageEnable = false;
	blendStateDesc.IndependentBlendEnable = false;
	blendStateDesc.RenderTarget[0].BlendEnable = true;
	blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MAX;
	blendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	return blendStateDesc;
}

ID3D11BlendState * QD3DUtils::createBlendState (
		const CD3D11_BLEND_DESC &blendDesc)
{
	ID3D11BlendState *pBlendState;
	__p_context->pDevice->CreateBlendState (&blendDesc, &pBlendState);
	return pBlendState;
}

void QD3DUtils::setBlendState (ID3D11BlendState *pBlendState,
		float *factors, UINT mask)
{
	float tempFactors[] = { 1.0, 1.0, 1.0, 1.0 };
	if (factors == NULL)
		factors = tempFactors;
	__p_context->pImmediateContext->OMSetBlendState (pBlendState, factors, mask);
}

ID3D11Query *QD3DUtils::createQuery (D3D11_QUERY queryType, UINT MiscFlags)
{
	ID3D11Query *query;
	D3D11_QUERY_DESC desc = { queryType, MiscFlags };
	HRESULT hr = __p_context->pDevice->CreateQuery (&desc, &query);
	if (FAILED (hr))
		throw std::exception ("QD3DUtils::createQuery()"
				"Fail to create query.");
	return query;
}

void QD3DUtils::beginDataCollection (ID3D11Asynchronous *pAsync)
{
	__p_context->pImmediateContext->Begin (pAsync);
}

void QD3DUtils::endDataCollection (ID3D11Asynchronous *pAsync)
{
	__p_context->pImmediateContext->End (pAsync);
}

bool QD3DUtils::getDataCollected (ID3D11Asynchronous *pAsync, void *pData,
		UINT size, bool waitForComplete)
{
	if (waitForComplete) {
		while (S_OK != __p_context->pImmediateContext->GetData (pAsync,
				pData, size, 0))
				;
		return true;
	} else {
		if (S_OK != __p_context->pImmediateContext->GetData (pAsync, pData,
				size, 0))
			return false;
		return true;
	}
}

void QD3DUtils::clearVertexBuffers (UINT startSlot, UINT num)
{
	QVector< ID3D11Buffer *> emptyBufferPtrs (num, NULL);
	QVector< UINT > emptyStrides (num, 0);
	QVector< UINT > emptyOffsets (num, 0);
	__p_context->pImmediateContext->IASetVertexBuffers (startSlot, num,
			&emptyBufferPtrs[0], &emptyStrides[0], &emptyOffsets[0]);
}

void QD3DUtils::clearIndexBuffer ()
{
	__p_context->pImmediateContext->IASetIndexBuffer (NULL, DXGI_FORMAT_UNKNOWN, 0);
}

